package experiment5.task;

import experiment5.utils.C3P0Tools;
import experiment5.utils.JDBCTools;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.Connection;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @Description:
 * @author:fyl
 * @date 2021/4/22 16:53
 * @Modified By:
 * @Modified Date:
 */
public class Server {
    private static JDBCTools<Message> jdbcTools = new JDBCTools<>();
    private static final String INSERT_SQL = "insert into chat_message(sid, sname, rid, rname, message,time) values (?,?,?,?,?,?)";

    private static final String QUERY_SQL = "select * from chat_message where sid = ? or rid = ?";
    private static CopyOnWriteArrayList<UserSocket> userList = new CopyOnWriteArrayList<>();

    //防止不同不用同名，加上id进行区分
    private HashMap<Integer, UserSocket> userMap;

    private static int count;

    public Server() {
        userMap = new HashMap<>();
    }

    public void start() {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(8080);
            System.out.println("服务器启动成功");
        } catch (IOException e) {
            e.printStackTrace();
            System.err.println("服务器启动失败");
        }

        try {
            while (true) {
                Socket socket = serverSocket.accept();
                //count依次递增作为唯一的id
                count += 1;
                UserSocket userSocket = new UserSocket(count, socket);
                userMap.put(count, userSocket);
                userList.add(userSocket);
                new Thread(userSocket).start();

                System.out.println("-----------------当前在线用户-------------------");
                userList.forEach(System.out::println);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    class UserSocket implements Runnable {
        //当前客户端对应的输入输出流
        private DataInputStream inputStream;
        private DataOutputStream outputStream;
        private int userId;
        private String userName;
        private boolean connection;

        public UserSocket(int userId, Socket socket) {
            this.userId = userId;
            try {
                inputStream = new DataInputStream(socket.getInputStream());
                outputStream = new DataOutputStream(socket.getOutputStream());
                connection = true;
            } catch (IOException e) {
                e.printStackTrace();
                connection = false;
                CloseUtil.closeAll(inputStream, outputStream);
            }

            try {
                this.userName = inputStream.readUTF();
                //播放系统公告
                sendOther("ID:" + this.userId + " name:" + this.userName + "已上线", true);
                send("你的ID为" + userId + "\n当前在线名单有:" + userList.toString());
            } catch (IOException e) {
                e.printStackTrace();
                connection = false;
                CloseUtil.closeAll(inputStream, outputStream);
            }
        }

        /**
         * 接受客户端发送的数据，用于转发操作
         *
         * @return 用户发送的数据
         */
        public String receive() {
            String msg = null;
            try {
                msg = inputStream.readUTF();
            } catch (IOException e) {
                e.printStackTrace();
                connection = false;
                CloseUtil.closeAll(inputStream, outputStream);
            }
            return msg;
        }

        /**
         * 发送数据到客户端
         *
         * @param msg 需要发送的数据
         */
        public void send(String msg) {
            try {
                outputStream.writeUTF(msg);
                outputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
                connection = false;
                CloseUtil.closeAll(inputStream, outputStream);
            }
        }

        /**
         * 转发数据判断方法，msg需要处理，同时要判断是否是系统发送消息
         *
         * @param msg 需要转发的消息
         * @param sys 系统标记
         */
        public void sendOther(String msg, boolean sys) {
            if (msg.startsWith("@") && msg.contains(":")) {
                //私聊
                Integer id = Integer.parseInt(msg.substring(1, msg.indexOf(":")));
                String newMsg = msg.substring(msg.indexOf(":") + 1);
                UserSocket userSocket = userMap.get(id);
                String receiveName = userSocket.getUserName();
                if (userSocket != null) {
                    userSocket.send("ID:" + this.userId + " name:" + this.userName + " 向你发消息:" + newMsg);
                    saveDate(id, receiveName, newMsg);
//                    Message message = new Message(this.userId, this.userName, id, receiveName, newMsg, timestamp);

                }
            } else {
                Collection<UserSocket> values = userMap.values();
                for (UserSocket userSocket : values) {
                    //不将消息发送给自己
                    if (userSocket != this) {
                        if (sys) {
                            userSocket.send("系统公告:" + msg);
                        }
//                        else {
//                            userSocket.send("ID:" + this.userId + " " + this.userName + msg);
//                        }
                    }
                }
            }
        }

        /**
         * 将消息存入数据库
         *
         * @param receiveID
         * @param receiveName
         * @param message
         * @return
         */
        public int saveDate(int receiveID, String receiveName, String message) {
            Connection connection = C3P0Tools.getConnection();
            //util.Date转换为sql.Date
            Date date = new Date();
            long time = date.getTime();
            Timestamp timestamp = new Timestamp(time);
            return jdbcTools.insertOrDeleteOrUpdateBean(connection, INSERT_SQL,
                    this.userId, this.userName, receiveID, receiveName, message, timestamp);
        }

        /**
         * 从数据库查询消息
         * @return
         */
        public String queryMessage() {
            StringBuilder result = new StringBuilder();
            Connection connection = C3P0Tools.getConnection();
            List<Message> list = jdbcTools.getBeans(connection, QUERY_SQL, Message.class, this.userId, this.userId);
            for (Message message : list) {
                result.append(message.toString()+"\n") ;
            }
            return result.toString();
        }

        public String getUserName() {
            return userName;
        }

        @Override
        public String toString() {
            return "{" +
                    "userId=" + userId +
                    ", userName='" + userName + '\'' +
                    '}';
        }

        @Override
        public void run() {
            while (connection) {
                // 使用receive收到的消息作为参数，同时标记非系统消息，调用sendOther
                String message = receive();
                if (message.equals("query")) {
                    send(queryMessage());
                }else {
                    sendOther(message, false);
                }
            }

        }
    }

    public static void main(String[] args) {
        Server server = new Server();
        try {
            server.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
